-
Notifications
You must be signed in to change notification settings - Fork 1
[FEAT] 길찾기 검색 연관 키워드 API #109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ring into feature/jeongbin
Walkthrough이 변경 사항은 길찾기(장소) 검색 연관 키워드 자동완성 API를 도입하고, 관련 엔티티, DTO, 저장소, 서비스, 컨트롤러 및 Elasticsearch 설정을 추가·수정합니다. 또한 TMap 관련 클래스의 패키지 구조를 통합하고, Swagger 문서화를 위한 인터페이스를 도입하였습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant DirectionController
participant DirectionService
participant PlaceRepository
participant DirectionElasticsearchRepository
participant ElasticsearchOperations
Client->>DirectionController: POST /api/v1/directions/place (PlaceSaveRequest)
DirectionController->>DirectionService: savePlaceAndIndexDocument(requests)
DirectionService->>PlaceRepository: saveAll(places)
PlaceRepository-->>DirectionService: List<Place>
DirectionService->>ElasticsearchOperations: bulkIndex(DirectionDocument)
ElasticsearchOperations-->>DirectionService: (완료)
DirectionService-->>DirectionController: (성공 메시지)
DirectionController-->>Client: CommonResponse<String>
Client->>DirectionController: GET /api/v1/directions/auto-complete?keyword=...
DirectionController->>DirectionService: searchDirection(keyword)
DirectionService->>DirectionElasticsearchRepository: searchDirection(DirectionSearchRequest)
DirectionElasticsearchRepository-->>DirectionService: List<DirectionSearchResponse>
DirectionService-->>DirectionController: List<DirectionSearchResponse>
DirectionController-->>Client: CommonResponse<List<DirectionSearchResponse>>
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes(해당 없음) Possibly related PRs
Suggested reviewers
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (5)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (2)
🔇 Additional comments (2)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🔭 Outside diff range comments (2)
src/main/java/com/wayble/server/common/config/WebClientConfig.java (1)
15-19: 기본 WebClient에 타임아웃·코덱 제한이 없어 잠재적 블로킹 위험
WebClient.builder().build()만 호출하면 커넥션/응답 타임아웃이 무제한입니다. 외부 API 장애 시 Netty 이벤트-루프가 장시간 블로킹되어 애플리케이션 전체 지연 가능성이 있습니다.return WebClient.builder() + .clientConnector(new ReactorClientHttpConnector(HttpClient.create() + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) + .responseTimeout(Duration.ofSeconds(5)))) .build();프로덕션 서비스라면 최소한의 타임아웃을 설정해 주세요.
src/main/java/com/wayble/server/common/client/tmap/TMapClient.java (1)
18-25: WebClientblock()호출로 인한 동기화·스레드 고갈 위험
API 클라이언트가block()으로 리액티브 스트림을 동기화하면, Netty 이벤트-루프 스레드를 점유하여 대기하게 되어 TPS가 증가할 때 심각한 병목이 발생할 수 있습니다. 서비스 전반이 WebFlux 스택이라면 Mono/Flux 를 그대로 반환해 호출 계층에서 비동기 처리하도록 변경하는 편이 안전합니다.- public TMapResponse response(TMapRequest request) { - return tMapWebClient.post() - .uri(tMapProperties.baseUrl()) - .header("appKey", tMapProperties.secretKey()) - .contentType(MediaType.APPLICATION_JSON) - .bodyValue(request) - .retrieve() - .bodyToMono(TMapResponse.class) - .block(); + public Mono<TMapResponse> response(TMapRequest request) { + return tMapWebClient.post() + .uri(tMapProperties.baseUrl()) + .header("appKey", tMapProperties.secretKey()) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(request) + .retrieve() + .bodyToMono(TMapResponse.class); }추가로
.onStatus(...)체인을 통해 오류 응답을 명확히 매핑하는 것을 권장합니다.
🧹 Nitpick comments (12)
src/main/resources/elasticsearch/settings/direction_settings.json (1)
10-14: edge_ngram 설정 범위가 인덱스 용량을 급격히 증가시킬 수 있습니다
min_gram: 2,max_gram: 20으로 설정하면 한국어 토큰 하나당 최대 19개의 n-gram이 생성되므로 인덱스 크기가 빠르게 불어날 수 있습니다. 실제 자동완성 UX에서 10자 이상 입력되는 경우가 드물다면max_gram을 10~15 정도로 줄여 디스크 사용량과 메모리 소비를 완화하는 방안을 검토해주세요.src/main/java/com/wayble/server/common/config/WebClientConfig.java (1)
22-26: TMap 전용 WebClient도 동일한 타임아웃·헤더 설정 권장
baseUrl만 지정되어 있고 공통 헤더(Authorization 등)나 타임아웃 설정이 없습니다. 외부 API SLA에 맞춰 동일하게 설정해 주세요.src/main/java/com/wayble/server/direction/controller/swagger/WalkingSwagger.java (1)
12-12: 태그 명칭 변경 통일성 확인
[길찾기 - 도보]형식으로 태그명이 변경되었습니다. 다른 Swagger 인터페이스(버스·자전거 등)가 있다면 동일한 네이밍 룰을 적용해 문서 내 섹션 정렬을 유지하는지 확인해주세요.src/main/java/com/wayble/server/common/client/tmap/mapper/TMapMapper.java (1)
21-84: null 안전성·복잡도 개선 제안
geometry,properties가 null 인 경우 NPE가 발생할 수 있고, 메서드 길이가 60+ 라인으로 가독성이 떨어집니다.
Objects.requireNonNull또는Optional로 빠른 방어-로직을 추가parsePointFeature,parseLineFeature등 서브 메서드로 분리해 책임을 명확히 할 것src/main/java/com/wayble/server/direction/dto/request/DirectionSearchRequest.java (1)
5-10: 검색 키워드name필수성 검증 누락
@Builder사용 시 모든 필드가 nullable 하게 생성되므로, 빈 문자열/ null 키워드가 ES 쿼리까지 전달될 수 있습니다.@NotBlank등 Bean Validation 어노테이션을 추가하여 컨트롤러 레이어에서 조기 검증해 주세요.import lombok.Builder; +import javax.validation.constraints.NotBlank; @Builder public record DirectionSearchRequest( - String name, + @NotBlank String name, Double latitude, Double longitude ) { }src/main/java/com/wayble/server/direction/entity/DirectionDocument.java (1)
3-3: 패키지 간 의존성에 대한 검토가 필요합니다.
EsAddress가explore.entity패키지에서 import되고 있는데,direction도메인에서explore도메인의 클래스를 사용하는 것이 적절한지 검토가 필요합니다. 공통 패키지로 이동하거나 별도의 direction용 Address 클래스를 생성하는 것을 고려해보세요.src/main/java/com/wayble/server/direction/dto/request/PlaceSaveRequest.java (1)
8-11: 입력 검증 어노테이션 추가를 고려해보세요.요청 DTO에
@Valid,@NotNull,@NotEmpty등의 검증 어노테이션을 추가하면 더 안전한 API가 될 수 있습니다.+import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; + @Builder public record PlaceSaveRequest( + @NotEmpty @Valid List<PlaceDetailRequest> requests ) {src/main/java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepositoryImpl.java (2)
23-23: 자동완성에는prefix쿼리가 더 적합할 수 있습니다현재
matches()메서드는 전체 텍스트 매칭을 수행합니다. 자동완성 기능의 경우 사용자가 입력 중인 부분 문자열에 대해 검색하므로prefix()또는wildcard()쿼리가 더 적절할 수 있습니다.- Criteria criteria = new Criteria("name").matches(request.name()); + Criteria criteria = new Criteria("name").startsWith(request.name());
26-26: 검색 결과 제한값을 설정 가능하도록 개선하드코딩된 값(5) 대신 설정 가능한 값으로 변경하는 것이 좋습니다.
@Value("${search.autocomplete.max-results:5}") private int maxResults;그리고 Line 26을:
- query.setMaxResults(5); + query.setMaxResults(maxResults);src/main/java/com/wayble/server/direction/controller/swagger/DirectionSwagger.java (1)
42-44:keyword파라미터에 대한 Swagger 문서화 추가
@RequestParam에@Parameter어노테이션을 추가하여 API 문서를 개선하세요.+import io.swagger.v3.oas.annotations.Parameter; CommonResponse<List<DirectionSearchResponse>> getDirectionKeywords( - @RequestParam String keyword + @Parameter(description = "검색할 키워드", required = true, example = "강남역") + @RequestParam String keyword );src/main/java/com/wayble/server/direction/service/DirectionService.java (1)
47-47: 인덱스 이름을 설정으로 관리하드코딩된 인덱스 이름을 설정 파일로 관리하는 것이 좋습니다.
@Value("${elasticsearch.index.direction:direction}") private String directionIndex;그리고:
- elasticsearchOperations.bulkIndex(queries, IndexCoordinates.of("direction")); + elasticsearchOperations.bulkIndex(queries, IndexCoordinates.of(directionIndex));src/main/java/com/wayble/server/direction/controller/DirectionController.java (1)
30-30: 키워드 파라미터 검증 추가컨트롤러 레벨에서 키워드 유효성 검증을 추가하면 좋습니다.
-public CommonResponse<List<DirectionSearchResponse>> getDirectionKeywords(@RequestParam String keyword) { +public CommonResponse<List<DirectionSearchResponse>> getDirectionKeywords( + @RequestParam @NotBlank(message = "검색 키워드는 필수입니다.") String keyword) {import 추가:
import jakarta.validation.constraints.NotBlank;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (25)
src/main/java/com/wayble/server/ServerApplication.java(2 hunks)src/main/java/com/wayble/server/common/client/tmap/TMapClient.java(1 hunks)src/main/java/com/wayble/server/common/client/tmap/TMapProperties.java(1 hunks)src/main/java/com/wayble/server/common/client/tmap/dto/request/TMapRequest.java(1 hunks)src/main/java/com/wayble/server/common/client/tmap/dto/response/TMapParsingResponse.java(1 hunks)src/main/java/com/wayble/server/common/client/tmap/dto/response/TMapResponse.java(1 hunks)src/main/java/com/wayble/server/common/client/tmap/mapper/TMapMapper.java(1 hunks)src/main/java/com/wayble/server/common/config/WebClientConfig.java(1 hunks)src/main/java/com/wayble/server/direction/controller/DirectionController.java(1 hunks)src/main/java/com/wayble/server/direction/controller/WalkingController.java(1 hunks)src/main/java/com/wayble/server/direction/controller/swagger/DirectionSwagger.java(1 hunks)src/main/java/com/wayble/server/direction/controller/swagger/WalkingSwagger.java(1 hunks)src/main/java/com/wayble/server/direction/dto/request/DirectionSearchRequest.java(1 hunks)src/main/java/com/wayble/server/direction/dto/request/PlaceSaveRequest.java(1 hunks)src/main/java/com/wayble/server/direction/dto/response/DirectionSearchResponse.java(1 hunks)src/main/java/com/wayble/server/direction/entity/DirectionDocument.java(1 hunks)src/main/java/com/wayble/server/direction/entity/Place.java(1 hunks)src/main/java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepository.java(1 hunks)src/main/java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepositoryImpl.java(1 hunks)src/main/java/com/wayble/server/direction/repository/DirectionElasticsearchRepository.java(1 hunks)src/main/java/com/wayble/server/direction/repository/PlaceRepository.java(1 hunks)src/main/java/com/wayble/server/direction/service/DirectionService.java(1 hunks)src/main/java/com/wayble/server/direction/service/WalkingService.java(1 hunks)src/main/resources/elasticsearch/settings/direction_mappings.json(1 hunks)src/main/resources/elasticsearch/settings/direction_settings.json(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: java에서 같은 패키지 내의 클래스들은 import 구문 없이 서로를 참조할 수 있다. com.wayble.server.user.entity 패키지 내의 클래스들은 명시적인 im...
Learnt from: seung-in-Yoo
PR: Wayble-Project/wayble-spring#37
File: src/main/java/com/wayble/server/user/entity/User.java:61-62
Timestamp: 2025-07-13T15:08:59.318Z
Learning: Java에서 같은 패키지 내의 클래스들은 import 구문 없이 서로를 참조할 수 있다. com.wayble.server.user.entity 패키지 내의 클래스들은 명시적인 import 없이 사용 가능하다.
Applied to files:
src/main/java/com/wayble/server/ServerApplication.javasrc/main/java/com/wayble/server/direction/entity/Place.java
🧬 Code Graph Analysis (1)
src/main/java/com/wayble/server/direction/dto/response/DirectionSearchResponse.java (1)
src/main/java/com/wayble/server/common/response/CommonResponse.java (1)
Builder(8-42)
🔇 Additional comments (18)
src/main/resources/elasticsearch/settings/direction_settings.json (1)
17-25: 검색 분석기와 인덱스 분석기의 필터 불일치 가능성 확인 필요
korean_edge_ngram_analyzer에는edge_ngram_filter가 포함되지만korean_search_analyzer에는 포함되지 않습니다. 이는 의도적으로 prefix 검색(자동완성)을 위한 구조로 보이나, 일반 검색 API도 동일한 인덱스를 쓸 경우 n-gram 갯수 차이로 점수 왜곡이 발생할 수 있습니다. 전체 검색과 자동완성을 별도 인덱스로 분리하지 않는다면, search time filter로edge_ngram_filter를 빼는 대신**query_type=phrase_prefix**등으로 해결하는 방법도 고려 바랍니다.src/main/resources/elasticsearch/settings/direction_mappings.json (1)
13-16: streetAddress 필드에 인덱스 분석기 미지정 – 검색 시 토큰 미스매칭 위험
현재streetAddress는search_analyzer만 지정되어 있어 색인 시에는 기본(Standard) Analyzer가 적용됩니다. 이렇게 되면
- 색인: Standard → 영어는 ok, 한글은 어절 단위
- 검색:
korean_search_analyzer(nori) → 형태소 단위
로 분석기가 달라져 매칭률이 급격히 떨어질 수 있습니다. 의도라면 주석으로 명시하고, 아니라면 다음과 같이 인덱스 분석기를 지정해주세요."streetAddress": { - "type": "text", - "analyzer": "korean_search_analyzer" + "type": "text", + "analyzer": "korean_search_analyzer", + "search_analyzer": "korean_search_analyzer" },또는 자동완성까지 고려한다면
korean_edge_ngram_analyzer사용을 권장합니다.Likely an incorrect or invalid review comment.
src/main/java/com/wayble/server/common/client/tmap/dto/request/TMapRequest.java (1)
1-14: 패키지 이동 확인 완료
패키지 변경 외에 로직 변경이 없으며record+@Builder사용도 적절합니다.src/main/java/com/wayble/server/common/client/tmap/dto/response/TMapResponse.java (1)
1-44: 패키지 이동 확인 완료
구조적 변화 없이 패키지만 일관성 있게 변경되었습니다.src/main/java/com/wayble/server/common/client/tmap/dto/response/TMapParsingResponse.java (1)
1-1: 패키지 이동으로 재사용성 및 모듈화 향상
direction.external.tmap패키지에서common.client.tmap패키지로 DTO를 이동한 결정이 일관성을 높이고 여러 모듈에서의 재사용성을 강화합니다. 별다른 부작용 없는 변경으로 판단됩니다.src/main/java/com/wayble/server/direction/controller/WalkingController.java (1)
6-7: 새 패키지 경로 반영 완료컨트롤러가 새로운 공통 TMap DTO 패키지를 제대로 참조하도록 수정되었습니다. 서비스 · 매퍼 계층과도 일치하므로 문제없습니다.
src/main/java/com/wayble/server/common/client/tmap/TMapProperties.java (1)
1-1: ConfigurationProperties 레코드에@ConstructorBinding여부 확인 필요Spring Boot 3.x 이상이면 자동으로 생성자 바인딩이 이뤄지지만, 2.x 계열을 사용 중이라면 레코드형
@ConfigurationProperties에는@ConstructorBinding(또는@EnableConfigurationProperties+스캔) 어노테이션이 추가되어야 합니다. 현행 부트 버전을 다시 한 번 확인해주세요.src/main/java/com/wayble/server/direction/service/WalkingService.java (1)
7-12: 공통 패키지 경로 적용 확인서비스가 새로 이동한 TMap 클라이언트 · DTO · 매퍼를 올바르게 의존하도록 변경되었습니다. DI 주입 및 빈 스캔 경로가 맞는지만 한번 더 빌드로 확인하면 충분합니다.
src/main/java/com/wayble/server/direction/controller/swagger/WalkingSwagger.java (1)
5-5: Swagger DTO import 경로 갱신 완료Swagger 인터페이스에서도 공통 패키지를 사용하도록 맞춰졌습니다. 문제없습니다.
src/main/java/com/wayble/server/ServerApplication.java (1)
18-20: Elasticsearch 리포지토리 스캔 범위 확인 필요
com.wayble.server.direction.repository패키지에는 JPA 리포지토리도 함께 존재할 가능성이 있습니다. 동일 패키지를 JPA·ES 양쪽에서 스캔하면 빈 충돌이 발생할 수 있으므로 디렉터리를 명확히 분리하거나includeFilters/excludeFilters설정을 고려해 주세요.src/main/java/com/wayble/server/direction/repository/PlaceRepository.java (1)
1-7: 변경 사항 문제없음
Spring Data JPA가 프록시 구현체를 자동 생성하므로 추가 어노테이션 없이도 정상 작동합니다.src/main/java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepository.java (1)
8-10: 인터페이스 설계가 깔끔합니다.검색 기능을 위한 커스텀 리포지토리 인터페이스가 잘 설계되었습니다. 메서드 시그니처도 적절하고 Spring Data 패턴을 잘 따르고 있습니다.
src/main/java/com/wayble/server/direction/repository/DirectionElasticsearchRepository.java (1)
6-7: 리포지토리 인터페이스 설계가 우수합니다.
ElasticsearchRepository와 커스텀 리포지토리를 함께 확장하여 표준 CRUD 기능과 커스텀 검색 기능을 모두 제공하는 좋은 설계입니다.src/main/java/com/wayble/server/direction/entity/Place.java (1)
32-37: 정적 팩토리 메서드가 잘 구현되었습니다.
of메서드를 통해 객체 생성을 간소화한 좋은 설계입니다. 빌더 패턴과 함께 사용하면 가독성이 높아집니다.src/main/java/com/wayble/server/direction/entity/DirectionDocument.java (3)
22-27: 한국어 분석기 설정이 적절합니다.
korean_edge_ngram_analyzer와korean_search_analyzer를 사용하여 한국어 자동완성 기능에 최적화된 설정입니다.
39-45: 엔티티 변환 메서드가 잘 구현되었습니다.JPA 엔티티에서 Elasticsearch 문서로의 변환을 깔끔하게 처리하고 있습니다. 정적 팩토리 메서드 패턴을 잘 활용했습니다.
13-15: Elasticsearch 설정 파일 확인 완료아래 파일들이 모두
src/main/resources/elasticsearch/settings/경로에 존재함을 확인했습니다:
- src/main/resources/elasticsearch/settings/direction_settings.json
- src/main/resources/elasticsearch/settings/direction_mappings.json
문제 없습니다.
src/main/java/com/wayble/server/direction/dto/request/PlaceSaveRequest.java (1)
13-17: 중첩 레코드 설계가 깔끔합니다.
PlaceDetailRequest를 중첩 레코드로 정의하여 관련성을 명확히 하고 코드 구조를 개선했습니다.
src/main/java/com/wayble/server/direction/controller/DirectionController.java
Show resolved
Hide resolved
src/main/java/com/wayble/server/direction/dto/response/DirectionSearchResponse.java
Show resolved
Hide resolved
.../java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepositoryImpl.java
Show resolved
Hide resolved
hyoinYang
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수고하셨습니다! 👍
hyoinYang
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
혹시 tmap 관련 패키지를 common으로 이동하신 이유가 무엇인가요??
저도 길찾기 쪽 외부 api 호출하는 부분을 common 디렉토리로 이동해야 하나 싶어서요!
큰 이유는 없지만 외부 API를 관리하는 건 common -> client에서 다 관리하는 게 좋을 것 같아서 이동했습니다! |
|
수고 많으셨습니다 정빈님! |
수정 완료 했습니다! |
✔️ 연관 이슈
📝 작업 내용
스크린샷 (선택)
Summary by CodeRabbit
신규 기능
API 변경
문서화
기타